package com.example.springboot.context;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.EmbeddedValueResolver;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.ApplicationStartupAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.lang.Nullable;
import org.springframework.util.StringValueResolver;

/**
 * 复制 ApplicationContextAwareProcessor 的源码
 * 直接展现org.springframework.context.support.ApplicationContextAwareProcessor的工作内容
 * <p>  负责在 Bean 初始化过程中，去回调各种 和容器环境相关的 Aware 接口
 *
 * <p> 检查 Bean 是否实现了某些 Aware 接口，如果是，就调用对应的 setter 方法，把容器相关对象注入进去 。
 *
 * @author Zhang.Z
 * @version 2025-09-21
 */
public class Test7ApplicationContextAwareProcessor {

    private final ConfigurableApplicationContext applicationContext;
    private final StringValueResolver embeddedValueResolver;

	public Test7ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
		this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
	}

    /**
     * 在此处，判断检查 Bean 是否实现了某些 Aware 接口，如果是，就调用对应的 setter 方法，把容器相关对象注入进去
     */
	@Nullable
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		if (!(bean instanceof EnvironmentAware) && !(bean instanceof EmbeddedValueResolverAware) && !(bean instanceof ResourceLoaderAware) && !(bean instanceof ApplicationEventPublisherAware) && !(bean instanceof MessageSourceAware) && !(bean instanceof ApplicationContextAware) && !(bean instanceof ApplicationStartupAware)) {
			return bean;
		} else {
//			AccessControlContext acc = null;
//			if (System.getSecurityManager() != null) {
//				acc = this.applicationContext.getBeanFactory().getAccessControlContext();
//			}
//
//			if (acc != null) {
//				AccessController.doPrivileged(() -> {
//					this.invokeAwareInterfaces(bean);
//					return null;
//				}, acc);
//			} else {
//				this.invokeAwareInterfaces(bean);
//			}

            this.invokeAwareInterfaces(bean);

			return bean;
		}
	}

    private void invokeAwareInterfaces(Object bean) {
        //用于获取EnvironmentAware的一个扩展类，这个变量非常有用， 可以获得系统内的所有参数。当然个人认为这个Aware没必要去扩展，因为spring内部都可以通过注入的方式来直接获得

        if (bean instanceof EnvironmentAware) {
            ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
        }

        //用于获取StringValueResolver的一个扩展类， StringValueResolver用于获取基于String类型的properties的变量，
        //一般我们都用@Value的方式去获取，如果实现了这个Aware接口，把StringValueResolver缓存起来，通过这个类去获取String类型的变量，效果是一样的

        if (bean instanceof EmbeddedValueResolverAware) {
            ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
        }

        //用于获取ResourceLoader的一个扩展类，ResourceLoader可以用于获取classpath内所有的资源对象，可以扩展此类来拿到ResourceLoader对象
        if (bean instanceof ResourceLoaderAware) {
            ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
        }

        //用于获取ApplicationEventPublisher的一个扩展类，ApplicationEventPublisher可以用来发布事件，结合ApplicationListener来共同使用，这个对象也可以通过spring注入的方式来获得
        if (bean instanceof ApplicationEventPublisherAware) {
            ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
        }

        //用于获取MessageSource的一个扩展类，MessageSource主要用来做国际化
        if (bean instanceof MessageSourceAware) {
            ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
        }

        //用来获取ApplicationContext的一个扩展类，ApplicationContext应该是很多人非常熟悉的一个类了，就是spring上下文管理器，
        //可以手动的获取任何在spring上下文注册的bean，我们经常扩展这个接口来缓存spring上下文，包装成静态方法。
        //同时ApplicationContext也实现了BeanFactory，MessageSource，ApplicationEventPublisher等接口，也可以用来做相关接口的事情
        if (bean instanceof ApplicationContextAware) {
            ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
        }
    }

}
